-- 运营活动: 摇钱树


--[[
{
    cmd_id = 1, -- 命令id，用于批量停止、删除活动 
    act_id = 50, -- 活动id (50 摇钱树)
    act_name = "摇钱树", -- 活动名称
    act_desc = "活动期间获取经验达到对应档次则可领取丰厚奖励！", -- 活动描述
    beg_time = 1493262000,  -- 活动开始时间(unix timestamp)
    end_time = 1593267400,  -- 活动结束时间(unix timestamp)
    config = -- 配置数据
    {
        exRewardMinGoldNum = 200000,    --最低奖池元宝个数
        exRewardFactor = 100,           --中奖概率 万分数
        exRewardNextFactor = {20, 10000},       --中奖奖金概率，万分数，与exRewardPrecent对应，必须长度相同，最后一位为10000
        exRewardPrecent = {0.2, 0.05},          --中奖奖金比例 

        Exchange =                          --抽奖相关
        {
            {
                ExchangeCount = 1,          --抽奖1次
                ExchangeMoneyType = 3,      --消耗类型 0金币 2绑元 3元宝
                ExchangeCost = 50,          --消耗数量
            },
            {
                ExchangeCount = 10,
                ExchangeMoneyType = 3,      --消耗类型 0金币 2绑元 3元宝
                ExchangeCost = 500,
            },
        },
        

        itemList =  
        {   
            {
                weight = 1,
                icon = 1,
                awards = 
                {
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                },
            },
            {
                weight = 1,
                icon = 1,
                awards = 
                {
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},          
                },
            },
            {
                weight = 1,
                icon = 1,
                awards = 
                {
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},              
                },
            },
            {
                weight = 1,
                icon = 1,
                awards = 
                {
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},      
                },
            },
            {
                weight = 1,
                icon = 1,
                awards = 
                {
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},      
                },
            },
            {
                weight = 1,
                icon = 1,
                awards = 
                {
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},
                    { weight = 1, type = 0, id = 802, count = 5,},          
                },
            },
        },  

        Rewards = 
        {
            {
                buyCount = 100,
                vipLevel = 0,   --所需vip等级
                Awards = 
                {       --第一档奖励
                    { type = 0, id = 518, count = 1, bind = 1, },
                    { type = 0, id = 559, count = 3, bind = 1, },
                },
            },
            {
                buyCount = 300,
                vipLevel = 0,   --所需vip等级
                Awards = 
                {       --第二档奖励
                    { type = 0, id = 518, count = 2, bind = 1, },
                    { type = 0, id = 559, count = 4, bind = 1, },
                },
            },
            {
                buyCount = 600,
                vipLevel = 0,   --所需vip等级
                Awards = 
                {       --第三档奖励
                    { type = 0, id = 518, count = 3, bind = 1, },
                    { type = 0, id = 559, count = 5, bind = 1, },
                },
            },
        },
    },
}
]]

-- 检查配置是否正确，正确则返回 0，否则返回错误码
function oper_act_50_check_cfg(cfg)
    if cfg == nil then return 20 end
    
    local config = cfg.config
    if config == nil then return 21 end
    
    if config.Rewards == nil then return 23 end
    if type(config.Rewards) ~= "table" then return 24 end
    for idx = 1, #config.Rewards do
        local dayRewards = config.Rewards[idx]
        if dayRewards == nil then return 25 end
        if type(dayRewards) ~= "table" then return 26 end
        local newDayRewards = dayRewards.Awards
        if newDayRewards == nil then return 27 end
        if type(newDayRewards) ~= "table" then return 28 end
        if not oper_act_check_one_award_cfg(newDayRewards) then
            return 22
        end 
    end

    if config.itemList == nil then return 29 end
    if type(config.itemList) ~= "table" then return 30 end
    for idx = 1, #config.itemList do
        local dayRewards2 = config.itemList[idx]
        if dayRewards2 == nil then return 31 end
        if type(dayRewards2) ~= "table" then return 32 end
        if dayRewards2.awards == nil then return 33 end
        if type(dayRewards2.awards) ~= "table" then return 34 end
        if not oper_act_check_one_award_cfg(dayRewards2.awards) then
            return 22
        end 
    end

    if config.Show == nil then return 35 end
    if type(config.Show) ~= "table" then return 36 end
    
    if not oper_act_check_one_award_cfg(config.Show) then
        return 22
    end 
    

    return 0
end

-- 安装活动，成功则返回 0，否则返回错误码
function oper_act_50_setup(cfg) 
    return 0
end

-- 卸载活动
function oper_act_50_unsetup(cfg)   
end

-- 活动开始
function oper_act_50_start(cfg)
    local ssVar = System.getStaticVar()
    ssVar.oper_act_50_start = 1
    ssVar.oper_act_50_cmd = cfg.cmd_id
    ssVar.oper_act_50_act = cfg.act_id

    local data = gRankMgr_GetValueByIndx(0, RANK_DEFINE_OPERATION_50, 1)

    if data then
        local myData = BaseFuc_unserialize(data)
        if myData and myData.cmd_id and myData.cmd_id == cfg.cmd_id and myData.act_id and myData.act_id == cfg.act_id and
            myData.time and cfg.beg_time <= myData.time and  cfg.end_time > myData.time then
            return
        end
    end

    ssVar.oper_act_50_total_buy_count = 0
    ssVar.oper_act_50_total_gold_count = 0

    gRankMgr_Clear(RANK_DEFINE_OPERATION_50)
end

-- 活动结束
function oper_act_50_end(cfg)
    local ssVar = System.getStaticVar()
    ssVar.oper_act_50_start = nil
    ssVar.oper_act_50_cmd = nil
    ssVar.oper_act_50_act = nil

    if not ssVar.oper_act_50_total_buy_count then
        ssVar.oper_act_50_total_buy_count = 0
    end

    if not cfg then return end
    local config = cfg.config
    if not config then return end

    local rankPtr = Ranking.getRanking(RankList[RANK_DEFINE_OPERATION_50].strName)
    local rankCount = Ranking.getRankItemCount(rankPtr)
    for idx = 1, rankCount do
        local item = Ranking.getItemFromIndex(rankPtr, idx-1)
        if item then
            local actorid = tonumber(Ranking.getId(item))
            local data = Ranking.getSub(item, 1)
            local dataTable
            if not data or data == "" then
                dataTable = {}
            else
                dataTable = BaseFuc_unserialize(data)
            end
          
            if dataTable.myBuyCount and dataTable.myBuyCount > 0 then
                local rewardCfg = config.Rewards
                for idx = 1, #config.Rewards do
                    if (dataTable.myDayData and dataTable.myDayData[idx] and dataTable.myDayData[idx] == 1) or
                        ((not dataTable.myDayData or not dataTable.myDayData[idx] or dataTable.myDayData[idx] == 0) and
                            ssVar.oper_act_50_total_buy_count >= config.Rewards[idx].buyCount and 
                            dataTable.myVip >= config.Rewards[idx].vipLevel)
                        then
                        local rewards = rewardCfg[idx].Awards
                        local title = Lang.ScriptTips.Operation131
                        local content = Lang.ScriptTips.Operation132
                        Awards.GiveToMailById(actorid, rewards, title, content, LogIds.OperationLogId050, Lang.LogTips.Operation050, dataTable.vocation, dataTable.sex)
                    end
                end
            end
        end
    end

    ssVar.oper_act_50_total_buy_count = nil
    ssVar.oper_act_50_total_gold_count = nil
end

-- 打包数据
function oper_act_50_packet_data(sysarg, cfg)

    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_50_start then
        return
    end

    local time = System.getSystemTime()

    
    if not cfg then
        return
    end

    local config = cfg.config
    if not config then
        return
    end

    
    local actorid = Actor.getActorId(sysarg)
    local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_50, 1)
    local myData = BaseFuc_unserialize(data)

    if not myData or myData == "" or myData == 0 then
        myData = {}
    end

    if not myData.myVip then
        myData.myVip = Actor.getVipGrade(sysarg)
    end

    if not myData.myBuyCount then
        myData.myBuyCount = 0
    end

    if not ssVar.oper_act_50_total_buy_count then
        ssVar.oper_act_50_total_buy_count = 0
    end


    local pack = oper_act_alloc_init_data_packet(sysarg, cfg.cmd_id, cfg.act_id)
    if (pack == nil) then
        return
    end

    DataPack.writeInt(pack, ssVar.oper_act_50_total_gold_count or 0)
    DataPack.writeInt(pack, ssVar.oper_act_50_total_buy_count or 0)
    local len = #config.Rewards
    DataPack.writeByte(pack, len)
    for idx = 1, len do
        DataPack.writeByte(pack, idx)
        local state = 0
        if myData.myDayData and myData.myDayData[idx] and myData.myDayData[idx] >= 1 then
            state = myData.myDayData[idx] 
        elseif (not myData.myDayData or not myData.myDayData[idx] or myData.myDayData[idx] == 0) and 
            ssVar.oper_act_50_total_buy_count >= config.Rewards[idx].buyCount and myData.myBuyCount and myData.myBuyCount > 0 and myData.myVip >= config.Rewards[idx].vipLevel then
            state = 1
        end
        DataPack.writeByte(pack, state)
        --print("state = "..state)
    end

    DataPack.flush(pack)

    --DataPack.writeByte(netPack, 1)        -- 活动特有参数
end

-- 操作，返回操作结果，0为成功
function oper_act_50_do(sysarg, cfg, clientPkt)
    if cfg == nil then return end
    
    if cfg.state == nil or cfg.state ~= 1 then -- 不在活动中
        Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation001, ttFlyTip)
        return
    end
    
    local config = cfg.config
    if config == nil then -- 参数错误
        print("error, oper_act_50_do cfg.config confg error")
        return
    end

    local operType = DataPack.readByte(clientPkt) 
    local Index = DataPack.readByte(clientPkt)

    --print("operType ="..operType)
    --print("Index ="..Index)

    local time = System.getSystemTime()

    --print("time ="..time)

    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_50_start then
        Actor.sendTipmsg(sysarg, Lang.ScriptTips.Operation004, ttFlyTip)
        return
    end

    local myRewards = {}
    local myExRewards = {}

    local myData

    if operType == 1 then

        local costConfig = config.Exchange[Index]
        if not costConfig then
            return
        end
        local bagEmptyNum = Item.getBagEmptyGridCount( sysarg )
        if costConfig.ExchangeCost > Actor.getMoneyCount(sysarg, config.ExchangeMoneyType) then
            local value = qatYuanbao
            if config.ExchangeMoneyType == 0 then
                value = qatBindMoney
            elseif config.ExchangeMoneyType == 2 then
                value = qatBindYb
            end
            Actor.sendItemLack( sysarg, value, 0, costConfig.ExchangeCost )
            return
        elseif bagEmptyNum < costConfig.ExchangeCount then
            Actor.sendTipmsg(sysarg, string.format(Lang.ScriptTips.Operation060, costConfig.ExchangeCount), ttFlyTip)
            return
        end
       
        local actorid = Actor.getActorId(sysarg)
        local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_50, 1)
        myData = BaseFuc_unserialize(data)

        if not myData then
            myData = {}
        end

        if not myData.myVip then
            myData.myVip = Actor.getVipGrade(sysarg)
        end

        if not Actor.changeMoney(sysarg, config.ExchangeMoneyType, -costConfig.ExchangeCost, LogIds.OperationLogId050, Lang.LogTips.Operation050) then
            return
        end
        if not ssVar.oper_act_50_total_buy_count then
            ssVar.oper_act_50_total_buy_count = 0
        end
        if not ssVar.oper_act_50_total_gold_count then
            ssVar.oper_act_50_total_gold_count = 0
        end
        ssVar.oper_act_50_total_buy_count = ssVar.oper_act_50_total_buy_count + costConfig.ExchangeCount
        ssVar.oper_act_50_total_gold_count = ssVar.oper_act_50_total_gold_count + costConfig.ExchangeCost


        if not myData.myBuyCount then
            myData.myBuyCount = 0
        end

        myData.myBuyCount = myData.myBuyCount + costConfig.ExchangeCount

        local totalMoneyNum = 0

        for ii = 1, costConfig.ExchangeCount do
            local iix, awardList = GetItemIdxRandExt(config.itemList)
            --print("iix ="..iix)
            local iixx, item = GetItemIdxRandExt(awardList.awards)
            --print("iixx ="..iixx)

            if item.broadcast and item.broadcast > 0 then
                local noticeStr = string.format(Lang.ScriptTips.Operation134, Actor.getName(sysarg), cfg.act_name, Item.getItemLinkMsg(item.id), item.count)
                System.broadcastTipmsg(noticeStr, ttScreenCenter + ttChatWindow)
            end

            table.insert(myRewards, item)

            --PrintAwardsTable({item})

            if ssVar.oper_act_50_total_gold_count >= config.exRewardMinGoldNum then
                local goldData = {}
                local ran = System.getRandomNumber(10000) + 1
                if ran <= config.exRewardFactor then
                    local ranValue = System.getRandomNumber(10000) + 1
                    for iii = 1, #config.exRewardNextFactor do
                        if ranValue <= config.exRewardNextFactor[iii] then
                            local getNum = config.exRewardPrecent[iii] * ssVar.oper_act_50_total_gold_count
                            totalMoneyNum = totalMoneyNum + getNum
                            ssVar.oper_act_50_total_gold_count = ssVar.oper_act_50_total_gold_count - getNum
                            goldData.index = ii
                            goldData.value = getNum
                            table.insert(myExRewards, goldData)

                            local moneyName = moneyTypeName[config.ExchangeMoneyType]
                            local msg = string.format(Lang.ScriptTips.Operation133, Actor.getName(sysarg), getNum, moneyName)
                            System.broadcastTipmsg(msg,ttScreenCenter + ttChatWindow)
                            break
                        end
                    end
                end
            end
        end
        
        if IsBagGridEnough(sysarg, myRewards) then
            GiveCommonAward(sysarg, myRewards, LogIds.OperationLogId050, Lang.LogTips.Operation050) 
        else
            local actorId = Actor.getActorId(sysarg)
            local title = Lang.ScriptTips.Operation131
            local content = Lang.ScriptTips.Operation132
            local sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
            local vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)
            Awards.GiveToMailById(actorId, myRewards, title, content, LogIds.OperationLogId050, Lang.LogTips.Operation050, vocation, sex)
        end

        if totalMoneyNum and totalMoneyNum > 0 then
            Actor.changeMoney(sysarg, config.ExchangeMoneyType, totalMoneyNum, LogIds.OperationLogId050, Lang.LogTips.Operation050) 
        end

        if not myData.cmd_id then
            myData.cmd_id = cfg.cmd_id
            myData.act_id = cfg.act_id
            myData.time = System.getSystemTime()
        end

        if not myData.sex then
            myData.sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
            myData.vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)
        end

        local newData = BaseFuc_serialize(myData)
        gRankMgr_SetRankEx(actorid, RANK_DEFINE_OPERATION_50, 1, newData)

    elseif operType == 2 then
       
        if Index > #config.Rewards then
            Actor.sendTipmsg(sysarg, Lang.ScriptTips.Operation005, ttFlyTip)
            return
        end

        local actorid = Actor.getActorId(sysarg)
        local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_50, 1)
        myData = BaseFuc_unserialize(data)

        if not myData then
            Actor.sendTipmsg(sysarg, Lang.ScriptTips.Operation006, ttFlyTip)
            return
        end

        if not myData.myVip then
            myData.myVip = Actor.getVipGrade(sysarg)
        end

        local getState = false
        if myData.myBuyCount and myData.myBuyCount > 0 and ((myData.myDayData and myData.myDayData[Index] and myData.myDayData[Index] == 1) or
            ((not myData.myDayData or not myData.myDayData[Index] or myData.myDayData[Index] == 0) and
                ssVar.oper_act_50_total_buy_count >= config.Rewards[Index].buyCount and myData.myVip >= config.Rewards[Index].vipLevel))
            then
            getState = true
        end

        if not getState  then
            Actor.sendTipmsg(sysarg, Lang.ScriptTips.Operation006, ttFlyTip)
            return
        end

        local rewardCfg = config.Rewards

        local rewards = rewardCfg[Index].Awards

        if not myData.myDayData then
            myData.myDayData = {}
        end

        myData.myDayData[Index] = 2
        
        if IsBagGridEnough(sysarg, rewards) then
            GiveCommonAward(sysarg, rewards, LogIds.OperationLogId050, Lang.LogTips.Operation050)
        else
            local actorId = Actor.getActorId(sysarg)
            local title = Lang.ScriptTips.Operation131
            local content = Lang.ScriptTips.Operation132
            local sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
            local vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)
            Awards.GiveToMailById(actorId, rewards, title, content, LogIds.OperationLogId050, Lang.LogTips.Operation050, vocation, sex)
        end

        if not myData.cmd_id then
            myData.cmd_id = cfg.cmd_id
            myData.act_id = cfg.act_id
            myData.time = System.getSystemTime()
        end

        if not myData.sex then
            myData.sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
            myData.vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)
        end

        local newData = BaseFuc_serialize(myData)
        gRankMgr_SetRankEx(actorid, RANK_DEFINE_OPERATION_50, 1, newData)
    end

    local netPack = oper_act_alloc_do_result_packet(sysarg, cfg.cmd_id, cfg.act_id, 0)
    if not netPack then return end
    
    DataPack.writeByte(netPack, operType)
    if operType == 1 then
        DataPack.writeInt(netPack, ssVar.oper_act_50_total_gold_count or 0)
        DataPack.writeInt(netPack, ssVar.oper_act_50_total_buy_count or 0)
        local len = #config.Rewards
        DataPack.writeByte(netPack, len)
        for idx = 1, len do
            DataPack.writeByte(netPack, idx)
            local state = 0
            if myData.myDayData and myData.myDayData[idx] and myData.myDayData[idx] >= 1 then
                state = myData.myDayData[idx] 
            elseif (not myData.myDayData or not myData.myDayData[idx] or myData.myDayData[idx] == 0) and 
                ssVar.oper_act_50_total_buy_count >= config.Rewards[idx].buyCount and myData.myBuyCount and myData.myBuyCount > 0 and myData.myVip >= config.Rewards[idx].vipLevel then
                state = 1
            end
            DataPack.writeByte(netPack, state)
        end

        local rewardlen = #myRewards
        DataPack.writeByte(netPack, rewardlen)
        for idxxx, v in ipairs(myRewards) do
            --print("v.type ="..v.type)
            DataPack.writeByte(netPack, v.type)
            --print("v.id ="..v.id)
            DataPack.writeShort(netPack, v.id)
            --print("v.count ="..v.count)
            DataPack.writeInt(netPack, v.count)
            DataPack.writeByte(netPack, v.bind or 1)
        end

        local exlen = #myExRewards 
        DataPack.writeByte(netPack, exlen)
        for idxxxx, exv in ipairs(myExRewards) do
            DataPack.writeByte(netPack, exv.index)
            DataPack.writeInt(netPack, exv.value)
        end
    else
        DataPack.writeByte(netPack, Index)
        DataPack.writeByte(netPack, 2)
    end

    DataPack.flush(netPack)
end

--[[
-- 跨天
function oper_act_50_new_day_arrive(act_id) 
   
end
]]

function oper_act_50_gmSetServerCount(num)
    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_50_start then
        return
    end
    ssVar.oper_act_50_total_buy_count = num
end

function oper_act_50_get_value_arrive(sysarg, value)
    if value <= 0 then
        return
    end

    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_50_start then
        return
    end
    if not ssVar.oper_act_50_cmd then
        return
    end
    if not ssVar.oper_act_50_act then
        return
    end
    
    local cfg = get_oper_act_cfg(ssVar.oper_act_50_cmd, ssVar.oper_act_50_act)
    if not cfg then
        return
    end

    local config = cfg.config
    if not config then
        return
    end 

    local actorid = Actor.getActorId(sysarg)
    local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_50, 1)
    local myData = BaseFuc_unserialize(data)

    if not myData then
        myData = {}
    end  

    myData.myVip = value
        
    if not myData.cmd_id then
        myData.cmd_id = cfg.cmd_id
        myData.act_id = cfg.act_id
        myData.time = System.getSystemTime()
    end

    if not myData.sex then
        myData.sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
        myData.vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)
    end

    local newData = BaseFuc_serialize(myData)
    gRankMgr_SetRankEx(actorid, RANK_DEFINE_OPERATION_50, 1, newData)

    oper_act_50_packet_data(sysarg, cfg)
    
end


